import cv2
import numpy as np

# 把图像均分成4份
def divide_four():
    rows, columns, channels = img.shape # 获取图像的行像素、列像素和通道数
    # 图像要被均分成2行2列的4幅图像
    for i in range(2):  # 表示“行”
        for j in range(2):  # 表示“列”
            # 使用“切片”，分别得到4幅图像中的每一幅图像
            img_roi = img[(i * int(rows / 2)):((i + 1) * int(rows / 2) - 1),
                      (j * int(columns / 2)):((j + 1) * int(columns / 2) - 1)]
            cv2.imshow(str(i) + "-" + str(j), img_roi)  # 窗口显示4幅图像中的每一幅图像

# 截取并保存图像
def cut_roi():
    # 选择图像内的感兴趣区域
    dst = cv2.selectROI("sculpture", img, True, False)
    # dst是一个元组类型，为元组中的各个元素设置标签
    x, y, w, h = dst
    if dst != (0, 0, 0, 0):  # 感兴趣区域被选择后
        roi = img[y:y + h, x:x + w]  # 把感兴趣区域赋值给一个标签
        cv2.imshow("roi", roi)  # 窗口显示感兴趣区域

def do_perspectivity():
    w, h = 320, 480
    tmp = cv2.GaussianBlur(img, (5, 5), 0)  # Canny边缘检测受噪声影响较大，先高斯滤波
    tmp = cv2.Canny(tmp, 50, 120)  # 变为二值边缘图像
    # 闭运算，二值边缘检测必须保证边缘闭合
    tmp = cv2.morphologyEx(tmp, cv2.MORPH_CLOSE, (15, 15), iterations=2)
    # 检测轮廓
    contours, _ = cv2.findContours(tmp, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    for c in contours:  # 遍历所有轮廓
        area = cv2.contourArea(c)  # 计算轮廓面积
        if area > 10000:  # 只处理面积廓大于10000的轮廓
            length = cv2.arcLength(c, True)  # 获取轮廓周长
            approx = cv2.approxPolyDP(c, 0.02 * length, True)  # 计算出轮廓的端点
            pts1 = np.float32(approx)  # 轮廓四个端点的坐标
            pts2 = np.float32([[w, 0], [0, 0], [0, h], [w, h]])  # 正面图对应的四个端点坐标
            M = cv2.getPerspectiveTransform(pts1, pts2)  # 创建透视图M矩阵
            tmp = cv2.warpPerspective(img, M, (w, h))  # 根据M矩阵做透视变换
    cv2.imshow("Top view", tmp)  # 展示俯视图

img = cv2.imread("book.jpg")
divide_four()
cut_roi()
do_perspectivity()
cv2.waitKey()
cv2.destroyAllWindows()